local skynet = require "skynet"
require "skynet.manager"
local GAMECMD = require "game_proto"
local CMD = require "game_proto"
require "dhmj"
require "chairaction"
local MJCONST =  require "const"
local TABLECONST = MJCONST.TABLECONST
local PAICONST = MJCONST.PAICONST
local WIKTYPE = MJCONST.WIKTYPE


local Seat = require "Seat"
local GameLogic = require "GameLogic"

function send_data(addr,msg)
    skynet.send(math.floor(addr),"lua","send_data",msg)
end

local TableLogic = GameLogic:extend()

TableLogic.TableConfig = {}

local TableConfig = TableLogic.TableConfig

local FANWAIFAN = {QINGYISE=0x0001,HAIDIHU=0x0002,HAIDIPAO=0x0004,GANGHUA=0x0008,GANGPAO=0x0010,QUANQIUREN=0x0020,QIANGGANGHU=0x0040,TIANHU=0x0080,DIHU=0x0100,MENQINIG=0x0200,QUANQIURENDIANPAO=0x0400,SHISANYAO=0x0800,ZIYISE=0x1000}

local MainCmdId = CMD.Main_ClientAndGameSvr_TableModle

TableLogic.CanChi = false   --是否支持吃

local nGameJuIndex = 0    --第几局

local GameState = {ready=0, play=1, conclude=3}  --开始前，游戏中，结算中

local function Increment(obj, userId, num, type)     --表，字段索引，要加的数
    local ind = userId + 1
    obj[ind] = (obj[ind] or 0) + num
    local strDes = {
        [1] = '分数', [2] = '胡 ',[3] = '刮风下雨 ',[5] = '点炮', [6] = '报听', [7] = '查叫', [8] = '反查'
    }
    --if type == 1 or type == 2 then print('!!!!!!!Increment id is ', userId, ' type is ', strDes[type], ' total is now ', obj[ind]) end
end

function TableLogic:initialize(room)
    TableLogic.meta.super.initialize(self,room)
    self.chairAddr={}
	self.chairAct={}
	self.chairIndex={}
	self.PlayerNum=3
	self.Banker=0
	self.CurUserId=0
	self.LeftCardCount=TABLECONST.PAI_TOTAL
	self.PingHuZiMo=false
    self.totalResult = {{},{},{},{},{},{},{},{}}
end

function TableLogic:InitGameData()
    for _,seat in pairs(self.m_pChairs) do
        seat.chairAction = {UserChairID=seat.m_wChairId, tabCbCardIndex = {},tabCbOutCard = {}, tabWeaveItem = {}, tabUserAction = {}, tabTingCardData={} }
	end
    self:InitChair()
	self:RegisterFun()
end

function TableLogic:InitChair()
    for i = 1, #self.chairIndex do
        local index = self.chairIndex[i]
        self.chairAct[index] = ChairAction:New(self.m_pChairs[index-1].chairAction)
        self.chairAct[index]:Init()
    end
end

function TableLogic:SetTableData(TableType, nMaxPlayerCount, nDiFen, nMa, nFangPaoOrZiMo, nDianPaoMaOrZiMoMa, nKeQiangGang, externData)
    skynet.error("TableType = ",TableType)
    local cpDes=""
    if TableType == 2 then --金币场写死或加载配制
        TableConfig.ZmJiaFan = false         --自摸加番
        TableConfig.JiPing = true
        TableConfig.FanCeil = 0                  --上限
        TableConfig.JiaFanZm = true            --加番需自摸
        cpDes = TableLogic:GetRoomInfo(externData, TableConfig)
    elseif TableType == 1 then
        cpDes = TableLogic:GetRoomInfo(externData)
    end

    self.PlayerNum = 3--nMaxPlayerCount 
    local strMakeRoomMsg = ' 豆花麻将 '..cpDes
    TableConfig.DiFen = nDiFen
    self:RegisterFun() 
    return strMakeRoomMsg
end

function TableLogic:GetRoomInfo(externData, defaultCfg)
    local strDes
    if defaultCfg then 
        TableConfig = defaultCfg 
        local zmjiafan, fanCeil, jp, jfzm = defaultCfg.ZmJiaFan, defaultCfg.FanCeil, defaultCfg.JiPing, defaultCfg.JiaFanZm
        local zmDes = {[false] = '自摸加底', [true] = '自摸加番'}
        local zfDes = {[false] = '加番可点炮',[true] = '加番需自摸'}
        local jxDes = {[0] = '', [2] = '2番', [3] = '3番', [4] = '4番'}
        local jpDes = {[false] = '', [true] = '极品'}
        strDes = string.format('%s %s %s %s 一人支付', zmDes[zmjiafan] or '', zfDes[jfzm] or '', jxDes[fanCeil] or '', jpDes[jp] or '')
    else
        local _, _, zmjiafan, fanCeil, jp, jfzm = string.unpack('iiiiii', externData)
        TableConfig.ZmJiaFan = (zmjiafan == 2)         --自摸加番
        TableConfig.JiPing = (jp ~= 0)
        TableConfig.FanCeil = fanCeil                  --上限
        TableConfig.JiaFanZm = (jfzm == 1)             --加番需自摸
        
        local zmDes = {[1] = '自摸加底', [2] = '自摸加番'}
        local zfDes = {[0] = '加番可点炮',[1] = '加番需自摸'}
        local jxDes = {[0] = '', [2] = '2番', [3] = '3番', [4] = '4番'}
        local jpDes = {[0] = '', [1] = '极品'}
        strDes = string.format('%s %s %s %s 一人支付', zmDes[zmjiafan], zfDes[jfzm], jxDes[fanCeil], jpDes[jp])
    end
    
    return strDes
end

function TableLogic:OnGameMessage(scmd,smsg,Player)
     skynet.error("[tableframe]",scmd)
     self:OnGameMsg(scmd, smsg, Player)
end

function TableLogic:OnGameMsg(scmd, smsg, Player)
    local data = string.sub(smsg, 5)
    local act = self.DoMsgList[scmd]
    if act then 
       self:DoMsg(act, data, Player) 
    end
end

function TableLogic:DoMsg(act, smsg, Player)
    local seat = self:GetSeatByPlayer(Player)
    local chair = seat.chairAction
    if chair then 
        local reciever = self
        if act.Reciever then reciever = act.Reciever end
        if act.UnPackFormat == '' then 
            act.Func(reciever, chair, act.Type)
        else
            if act.Type then 
                act.Func(reciever, chair, act.Type, string.unpack(act.UnPackFormat, smsg))
            else 
				act.Func(reciever, chair, string.unpack(act.UnPackFormat, smsg))
            end
        end
    end
end

function TableLogic:OnSitDownSucess(seat)
    local GAME_ID = tonumber(skynet.getenv('game_id')) or 1001 
    skynet.error("self.PlayerNum = ",self.PlayerNum)
    local msg = string.pack(">I2>I2<I4<I4", 303, 2070, GAME_ID, self.PlayerNum)    --再告诉客户端几人麻将
    self:send_data(seat,msg)

    local chairAct = seat.chairAction
    chairAct.addr = seat.Player.nAgentAddr
    chairAct.PlayerId = seat.Player.nPlayerId
    self.chairAddr[chairAct.addr] = chairAct
end

function TableLogic:UserComeBack(seat)
    local GAME_ID = tonumber(skynet.getenv('game_id')) or 1001 
    local msg = string.pack(">I2>I2<I4<I4", 303, 2070, GAME_ID, self.PlayerNum)    --再告诉客户端几人麻将
    self:send_data(seat,msg)

    local chairAct = seat.chairAction
    chairAct.addr = seat.Player.nAgentAddr
    chairAct.PlayerId = seat.Player.nPlayerId
    self.chairAddr[chairAct.addr] = chairAct
end
 
function TableLogic:ConcluedGameLastRound()
    local dataBuf = ''
    local total = self.totalResult
    for i = 1, #total do
        for j = 1, 4 do
            dataBuf = dataBuf..string.pack('i4', total[i][j] or 0)
        end
    end
    dataBuf = dataBuf..string.pack('i', self.LiuJuNum or 0)
    local endtime = tostring(os.date("%Y-%m-%d %H:%M:%S",os.time()))
    dataBuf = dataBuf..endtime
    dataBuf = dataBuf..BufTool.WriteOffset(32 - string.len(endtime))
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_8JuGameOver, dataBuf)
    self.totalResult = {{},{},{},{},{},{},{},{}}
    nGameJuIndex = 1
    return true
end

function TableLogic:OneJuOver()
	
end

function TableLogic:GetSeatCount()
	self.chairIndex = {1,2,3}
    return 3,self.chairIndex
end

function TableLogic:RegisterFun()
	self.DoMsgList = {}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_StandUpReq]       = {UnPackFormat = '',  Func = TableLogic.StandUp}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_OutCardReq]       = {UnPackFormat = 'B', Func = TableLogic.OnOutCard}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoAnGangReq]      = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_ANGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelAnGangReq]   = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_ANGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoJiaGangReq]     = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_JIAGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelJiaGangReq]  = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_JIAGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelJieGangReq]  = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_JIEGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelPengReq]     = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_PENG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoJieGangReq]     = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_JIEGANG}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoPengReq]        = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_PENG}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoDuGangReq]      = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_DU}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoHuReq]          = {UnPackFormat = 'B', Func = TableLogic.DoActionReq,     Type = WIKTYPE.WIK_HU}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CancelHuReq]      = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_HU}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_DoChiReq]         = {UnPackFormat = 'BBB', Func = TableLogic.DoActionReq,   Type = WIKTYPE.WIK_LINE}
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_CanelChiReq]      = {UnPackFormat = '',  Func = TableLogic.CancelActionReq, Type = WIKTYPE.WIK_LINE}
    
    self.DoMsgList[GAMECMD.Sub_ClientToGameSvr_TableModle_ReportTingResp]   = {UnPackFormat = 'i2',  Func = TableLogic.ProcBaoTingOrNot}
    
    --TableLogic:RegisterFun()
    self.actFun = {}
    self.actFun[WIKTYPE.WIK_LINE]    = TableLogic.DoCommonActReq
    self.actFun[WIKTYPE.WIK_PENG]    = TableLogic.DoCommonActReq
    self.actFun[WIKTYPE.WIK_JIAGANG] = TableLogic.DoGangActReq
    self.actFun[WIKTYPE.WIK_JIEGANG] = TableLogic.DoGangActReq
    self.actFun[WIKTYPE.WIK_ANGANG]  = TableLogic.DoGangActReq
    --self.actFun[WIKTYPE.WIK_HU]      = TableLogic.DoHuReq
    --self.actFun[WIKTYPE.WIK_DU] = TableLogic.DoGangActReq
end

function TableLogic:ProcBaoTingOrNot(chair, type)
    print('^^^^^^^^ chair baoting is ', chair.UserChairID, (type or -1))
    chair.DoneBaoTing = type
    self.CouldBaoTing = self.CouldBaoTing - 1
    local msg = string.pack('i2b', chair.UserChairID, type)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UpdateBaoTingState, msg)
    if type > 0 then 
        Increment(self.totalResult[6], chair.UserChairID, 1, 6)
    end
    if self.CouldBaoTing == 0 then 
        local msg = string.pack('i2b', chair.UserChairID, type)
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_FinishReportTing, msg)
        self.PermitOutCard = true
        self:DispatchCard(self:UserIdToChair(self.Banker))
    end
end

function TableLogic:DoGangActReq(type, chair, centerCard)      --杠
    if type == WIKTYPE.WIK_JIAGANG then   --可以抢杠胡
        if self:CheckQiangGangHu(type, chair, centerCard) then
            local ind = MjLogic:ValToIndex(centerCard)
            chair.tabCbCardIndex[ind] = chair.tabCbCardIndex[ind] - 1
            local bufData = string.pack('<I2B<IIII', chair.UserChairID, centerCard, 0,0,0,0)
            self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoJiaGangOk, bufData)
            chair.tabUserAction:Reset()
            chair.tabToDo = nil
            chair:UpdataTingData()
            return
        end
    end
    local provider = chair:DoChiPengGangActReq(chair.DoMsgList[type], centerCard)    --暗杠的provider是自己
    if provider then
        if type == WIKTYPE.WIK_JIEGANG then self:SetNextUser() end  --接杠
        self:DoActionCmd(type, chair, provider, centerCard)
        self:DispatchCard(chair, type)
        
         for k, v in pairs(chair.tabWeaveItem) do     --记录杠牌时摸的牌，用于计算杠花，杠炮
            if v.Kind == type then 
                chair.tabWeaveItem[k].dispatchCardInfo = self.tabCurGetCard
                chair.tabWeaveItem[k].dispatchCardInfo.outCardCount = chair.OutCardCount
                break
            end
        end
        
    end
end

function TableLogic:MakeReadyTable()   
    self.CurUserId = 0
    self.LeftCardCount = TABLECONST.PAI_TOTAL
    self.HasDoHu = 0
    self.HasConclude = false
    self.tabGang = {}
    self.FanJiangRepeat = 0
    self.PermitOutCard = false
    self.ProcMaiZhuangNum = 0
    self.DoneLLCount = 0
    self.tabLiaoLongGetCardNum = {}
    self.tabJiang = {}
    self.tabCurGetCard = {}   -- 当前摸牌了的牌值和人Id，不一定是正在出牌的人，因为有碰杠
    
    function ClearChairInTable(chair)    --只清空在Table用到chair数据
        chair.DoneLiaoLong = false
        chair.tabXiPai = {}
        chair.MaiZhuang = -1
        chair.GameState = GameState.ready
        chair.tuoguan = false
    end

    for chair in self:ChairIterator() do
        chair:MakeReadyChair(self)
        ClearChairInTable(chair)
    end
end

function TableLogic:OnPlayerOfflineBack(seat)
    --local chair = self:UserIdToChair(seat.m_wChairId)
    --chair.addr = seatPlayer.nAgentAddr                          --重新获得地址
    --self.chairAddr[chair.addr] = chair
    self:SendMeOfflineBackData(seat.Player, seat.m_wChairId)
end

function TableLogic:OnEventGameStart()
	self:MakeReadyTable()
    for chair in self:ChairIterator() do
       chair.GameState = GameState.play 
    end
	self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_GameStart)
	self:MjLogicBegin()
end

function TableLogic:OneJuOver()
    self.TableObj.m_wCurJu = self.TableObj.m_wCurJu + 1 
end

function TableLogic:StandUp(chair)
	local msg = string.pack('<I2', chair.UserChairID)
	self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_PlayerQuit, msg)
end

function TableLogic:DoActionReq(chair, type, centerCard, cardBef, cardAft)
    if type == WIKTYPE.WIK_HU then 
        -- if self:WaitForOtherActs(chair, type, centerCard, cardBef, cardAft) then    --点胡了,但是因为有其他玩家也胡,暂时胡不了
        -- else 
            -- self:DoHuReq(chair, centerCard)    --只有一家胡
        -- end
        self:DoHuReq(chair, centerCard)    --只有一家胡
    else 
        if self.actFun[type] then self.actFun[type](self, type, chair, centerCard, cardBef, cardAft) end
    end    
end

function TableLogic:DoHuReq(chair, getCardData)
    if chair.DoneHu then return end    --防止重复
    self.CurUserId = chair.UserChairID
    local huInfo = chair:DoHu(getCardData)
    if huInfo then
        self:DoHuCmd(chair, getCardData, huInfo)
    end
end

function TableLogic:DoHuCmd(chair, getCardData, huInfo)
    if chair.DoneHu then return end    --防止重复
    self.HasDoHu = self.HasDoHu + 1
    chair.DoneHu = true
    
    local bZiMo = false
    if huInfo.Provider then 
        local dPChair = self:UserIdToChair(huInfo.Provider)     --点炮者
        dPChair.tabHuInfo.DianPaoInfo = dPChair.tabHuInfo.DianPaoInfo or {}
        table.insert(dPChair.tabHuInfo.DianPaoInfo, {Id = chair.UserChairID, Lc = self.LeftCardCount})
        Increment(self.totalResult[5], huInfo.Provider, 1, 5)
    else bZiMo = true end
    
    chair.tabHuInfo = {Hu=true,HuType=huInfo.HuType,CardData=getCardData,ZiMo=bZiMo,ProviderId=huInfo.Provider}
    self.Huer = self.Huer or {}
    table.insert(self.Huer, {Id=chair.UserChairID,ZiMO=bZiMo,ProviderId=huInfo.Provider,Lc=self.LeftCardCount})    --计算新的庄家时用到
    local fan = huInfo.fan or 0
    if huInfo.QGHu then fan = fan | FANWAIFAN.QIANGGANGHU chair.tabHuInfo.QGHu = true end
    fan = fan | chair:GetFanWaiFan()
    
    function HasFan(name)
        local tabFan = {
            ['tianhu']       = FANWAIFAN.TIANHU,
            ['dihu']         = FANWAIFAN.DIHU,
            ['ganghua']      = FANWAIFAN.GANGHUA,
            ['gangpao']      = FANWAIFAN.GANGPAO,
            ['qingyise']     = FANWAIFAN.QINGYISE,
            ['qiangganghu']  = FANWAIFAN.QIANGGANGHU,
        }
        if (fan & (tabFan[name] or 0)) ~= 0 then return 1
        else return 0 end
    end
    local bufData = string.pack('<I2B<IIIIIIIIIIB', chair.UserChairID, huInfo.HuType, HasFan('qingyise'),HasFan('gangpao'), 
    HasFan('ganghua'), 0, 0, HasFan('qiangganghu'), 0, HasFan('tianhu'), HasFan('dihu'), 0, getCardData)
    
    chair.tabHuInfo.Fan = fan
    
    local tabPerScore = self:CalScore(chair.UserChairID, huInfo.Provider)   
    for i = 0, 3 do
        bufData = bufData..string.pack('i', (tabPerScore[i] or 0))
    end
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_HuPai, bufData)
    Increment(self.totalResult[2], chair.UserChairID, 1, 2)
    
    for chair in self:ChairIterator({OmitHuer = true}) do
        local tempAct = {} 
        for k, v in ipairs(chair.tabUserAction) do
            if v.Type == WIKTYPE.WIK_HU and v.CardData == getCardData then    --一个玩家胡了之后，要重新发消息给其他玩家，因为其他玩家可能有碰，让碰消失
                table.insert(tempAct, v)
                break
            end
        end
        chair.tabUserAction:Reset()
        chair.tabUserAction[1] = tempAct[1]
        chair:SendOperateHint(true)
    end
    
    if self.HasDoHu == 2 then     --有两个人胡了就结算
        local HuData = {HuId = chair.UserChairID, HuCardData = getCardData, HuType = huInfo.HuType, ZiMo = bZiMo, Fan = fan}
        self:GameOver(HuData)
    else 
        local otherActNum = self:OtherChairsHasMoreAct(chair, WIKTYPE.WIK_HU)
        if otherActNum == 0 then    --其他玩家没有胡牌
            self:SetNextUser()               
            local chair = self:UserIdToChair(self.CurUserId)
            chair.tabUserAction:Reset()
            self:DispatchCard()
        end
    end
end

function TableLogic:DoCommonActReq(type, chair, centerCard, cardBef, cardAft)      --吃,碰
    local provider = chair:DoChiPengGangActReq(chair.DoMsgList[type], centerCard, cardBef, cardAft)
    if provider then 
        self:SetNextUser()
        self:DoActionCmd(type, chair, provider, centerCard, cardBef, cardAft)

        if provider ~= chair.UserChairID then 
            local pc = self:UserIdToChair(provider)
            if pc then
                table.remove(pc.tabCbOutCard, #pc.tabCbOutCard)  --收回该牌，断线重连的时候用到    
            end
        end
    end
end


function TableLogic:DoActionCmd(type, chair, provider, centerCard, cardBef, cardAft)
    local wUserChairId = chair.UserChairID
    self.CurUserId = chair.UserChairID
    local dataBuf = ''
    
    function CalGangScore(type)
        local gangscores = {0,0,0,0}
        if type == WIKTYPE.WIK_ANGANG then 
            local anGangTotal = 0
            for ch in self:ChairIterator({OmitHuer = true, CurId = wUserChairId}) do
                ch.GameScoreJu = (ch.GameScoreJu or 0) - 2
                gangscores[ch.UserChairID + 1] = -2
                anGangTotal = anGangTotal + 2
                print(string.format('$$$$$$$$$AnGang, Id %d lost %d',ch.UserChairID, 2))
                --ch.GangDes = ch.GangDes or ''
               -- ch.GangDes = ch.GangDes..string.format(' 暗杠%d分 ', -2)
                ch.GangScore = (ch.GangScore or 0) - 2 
            end
            chair.GameScoreJu = (chair.GameScoreJu or 0) + anGangTotal
            gangscores[chair.UserChairID + 1] = anGangTotal
            print(string.format('$$$$$$$$$AnGang, Id %d win %d',chair.UserChairID, anGangTotal))
            --chair.GangDes = chair.GangDes or ''
            --chair.GangDes = chair.GangDes..string.format(' 暗杠%d分 ', anGangTotal)
            chair.GangScore = (chair.GangScore or 0) + anGangTotal 
        elseif type == WIKTYPE.WIK_JIAGANG then
            local jiaGangTotal = 0
            for ch in self:ChairIterator({OmitHuer = true, CurId = wUserChairId}) do
                ch.GameScoreJu = (ch.GameScoreJu or 0) - 1
                gangscores[ch.UserChairID + 1] = -1
                jiaGangTotal = jiaGangTotal + 1
                print(string.format('$$$$$$$$$JiaGang, Id %d lost %d',ch.UserChairID, 1))
                --ch.GangDes = ch.GangDes or ''
                --ch.GangDes = ch.GangDes..string.format(' 巴杠%d分 ', -1)
                ch.GangScore = (ch.GangScore or 0) - 1
            end
            chair.GameScoreJu = (chair.GameScoreJu or 0) + jiaGangTotal
            gangscores[chair.UserChairID + 1] = jiaGangTotal
            chair.GangScore = (chair.GangScore or 0) + jiaGangTotal 
            print(string.format('$$$$$$$$$JiaGang, Id %d win %d',chair.UserChairID, jiaGangTotal))
        elseif type == WIKTYPE.WIK_JIEGANG then 
            chair.GameScoreJu = (chair.GameScoreJu or 0) + 2
            gangscores[chair.UserChairID + 1] = 2
            print(string.format('$$$$$$$$$JieGang, Id %d win %d',chair.UserChairID, 2))
            --chair.GangDes = chair.GangDes or ''
            --chair.GangDes = chair.GangDes..string.format(' 直杠%d分 ', 2)
            chair.GangScore = (chair.GangScore or 0) + 2 
            local chProvider = self:UserIdToChair(provider)
            if chProvider then 
                chProvider.GameScoreJu = (chProvider.GameScoreJu or 0) - 2
                gangscores[chProvider.UserChairID + 1] = -2
                print(string.format('$$$$$$$$$jieGang, Id %d lost %d',provider, 2))
                --chProvider.GangDes = chProvider.GangDes or ''
                --chProvider.GangDes = chProvider.GangDes..string.format(' 直杠%d分 ', -2)
                chProvider.GangScore = (chProvider.GangScore or 0) - 2
            end
        else
        end
        return gangscores
    end
    
    local gangscores = CalGangScore(type)
    
    if type == WIKTYPE.WIK_PENG then 
        dataBuf = dataBuf..string.pack('<I2B<I2<I2', wUserChairId, centerCard, provider, wUserChairId)
        dataBuf = dataBuf..chair.tabUserAction:GetPackString()
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoPengOk, dataBuf)
        
    elseif type == WIKTYPE.WIK_LINE then 
        dataBuf = dataBuf..string.pack('<I2B<I2<I2BB', wUserChairId, centerCard, provider, wUserChairId, cardBef, cardAft)
        chair.tabUserAction:Reset()
        dataBuf = dataBuf..chair.tabUserAction:GetPackString()
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoChiOk, dataBuf)
        
    elseif type == WIKTYPE.WIK_JIEGANG then 
        local bufData = string.pack('<I2B<I2iiii', wUserChairId, centerCard, provider, gangscores[1], gangscores[2], gangscores[3], gangscores[4])
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoJieGangOk, bufData)
        Increment(self.totalResult[3], wUserChairId, 1, 3)
        
    elseif type == WIKTYPE.WIK_JIAGANG then 
        local bufData = string.pack('<I2B<iiii', wUserChairId, centerCard, gangscores[1], gangscores[2], gangscores[3], gangscores[4])
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoJiaGangOk, bufData)
        Increment(self.totalResult[3], wUserChairId, 1, 3)
        
    elseif type == WIKTYPE.WIK_ANGANG then 
        local bufData = string.pack('<I2B<iiii', wUserChairId, centerCard, gangscores[1], gangscores[2], gangscores[3], gangscores[4])
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserDoAnGangOk, bufData)
        Increment(self.totalResult[3], wUserChairId, 1, 3)
    end
    
end

function TableLogic:WaitForOtherActs(chairAct, type, centerCard, cardBef, cardAft, provider)
    local otherActNum = self:OtherChairsHasMoreAct(chairAct, type)
    if otherActNum > 0 then
        chairAct:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_WaitingForAnotherHu)
        chairAct.tabToDo = {}
        chairAct.tabToDo.Num = otherActNum
        chairAct.tabToDo.Func = chairAct.DoDelayAction
        chairAct.tabToDo.tabParam = {type, {centerCard, cardBef, cardAft}, provider}
        chairAct.OperateBit = 0
        return true 
    end
    return false
end

function TableLogic:OtherChairsHasMoreAct(chairAct, type)
    local oneAct = 0
    for otherChair in self:ChairIterator({OmitHuer = true}) do
        if otherChair.UserChairID ~= chairAct.UserChairID then
            otherChair.OperateBit = otherChair.OperateBit or 0
            if type*otherChair.OperateBit > 0 and otherChair.OperateBit >= type then
                print(string.format('##########chairAct id is %d, others is %d, type is %d', chairAct.UserChairID, otherChair.UserChairID, type))
                oneAct = oneAct + 1
            end
        end
    end
    return oneAct
end

function TableLogic:CheckQiangGangHu(type, chair, centerCard)
    local oneHu = 0
    for ch in self:ChairIterator({CurId = chair.UserChairID}) do
        local couldHu = ch:CanHu(centerCard, chair.UserChairID)
        if couldHu then 
            ch.OperateBit = ch.OperateBit|WIKTYPE.WIK_HU|WIKTYPE.WIK_QGHU
            local msg = ch.tabUserAction:GetPackString()
            ch:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_CanDianPaoHu, msg)
            oneHu = oneHu + 1
        end
    end
    
    return oneHu > 0
end

function TableLogic:CancelActionReq(chair, type)
    if chair:CancelActionReq(type) then      --取消成功,可能会重复发送消息
        chair.OperateBit = 0
        
        for otherChair in self:ChairIterator({OmitHuer = true}) do        --取消时其他玩家可能还有操作未被执行,例如有玩家1碰,玩家2胡,2取消
            if otherChair.UserChairID ~= chair.UserChairID then
                if otherChair.tabToDo and otherChair.tabToDo.tabParam then 
                    if not otherChair.tabToDo.Num then otherChair.tabToDo.Num = 1 end   
                    otherChair.tabToDo.Num = otherChair.tabToDo.Num - 1 
                    local param = otherChair.tabToDo.tabParam    --type, tabCardData, provider
                    if otherChair.tabToDo.Num == 0 or self:OtherChairsHasMoreAct(otherChair, param[1]) == 0 then  --例如抢杠时，有两个人可以胡，只有这两个人都取消后才能继续杠 
                        otherChair.tabToDo.Func(otherChair, param[1], param[2], param[3])
                        otherChair.tabToDo = nil
                        return
                    end
                end 
            end            
        end
       
        for otherChair in self:ChairIterator({OmitHuer = true}) do    --其他玩家没有同样的动作(一般是胡)要处理,有多响时要检测
            if otherChair.UserChairID ~= chair.UserChairID and #otherChair.tabUserAction > 0 then
                for i = 1, #otherChair.tabUserAction do
                    if otherChair.tabUserAction[i].Type == type then    --玩家取消胡，如果下一家可以胡，则让他显示
                        otherChair:SendOperateHint()
                        return 
                    end
                end
            end
        end
        
        for chair in self:ChairIterator({OmitHuer = true}) do       --其他玩家有动作,比如取消点炮,可能下个玩家有吃(因为有胡,吃时,吃没有显示出来)
            if #chair.tabUserAction > 0 then 
                self.CurUserId = self.LastOutCardId
                chair:SendOperateHint()
                return 
            end
        end
           
        if self.CurUserId ~= chair.UserChairID then   --取消暗杠,加杠,自摸胡不需要转移到其他玩家
            self:SetNextUser()
            self:DispatchCard()
        end
    end
end

function TableLogic:MjLogicBegin()
    local total_num = TABLECONST.PAI_TOTAL
    MjLogic:Init(total_num)
    MjLogic:randCard(1)
    self:RandomFromConfig(MjLogic.table_RepertoryCard)
    nGameJuIndex = nGameJuIndex + 1
    self:StartFaPai(nGameJuIndex)
    
end

function TableLogic:RandomFromConfig(tab_RandCard)    
    local fapai_server = skynet.getenv('fapai_server')
    local fapai_file = skynet.getenv('fapai_file')
    local Tables 
    if fapai_server and fapai_file then 
        local httpc = require "http.httpc"
        local status, body =  httpc.get(fapai_server, fapai_file, {})
        skynet.error('get fapai from ', (fapai_server or ''), (fapai_file or ''), 'status is', status)
        local TablesFun = load(body)
        if TablesFun then Tables = TablesFun() end
        if not Tables then skynet.error('parse FaPai.lua error') return end 
    else    
        local logicPath = skynet.getenv('gamelogic_path')
        if not logicPath then return end
        skynet.error('logicPath is'..logicPath)
        local fileFaPai = io.open(logicPath..'FaPai.lua',rb)
        if fileFaPai then fileFaPai:close() 
        else skynet.error('no fapai file!!!') return end
        Tables = require("FaPai")
    end

    local Table
    for chair in self:ChairIterator() do
        if Tables[chair.PlayerId] ~= nil then
            Table = Tables[chair.PlayerId]
            break
        end
    end
    for _, seat in pairs(self.m_pChairs) do       --根据Ip地址来
        if Tables[seat.Player.szIp] ~= nil then
            Table = Tables[seat.Player.szIp]
            break
        end
    end
    if not Table then skynet.error('no Id of the plays!!!') return end     --没有该玩家的脚本
    
    if not Table.Enable then return end     --没有开启
    if not Table.endPai then Table.endPai = {} end
    local cuRepertoryCard = {}
    for i = 1, TABLECONST.PAI_TOTAL do
        cuRepertoryCard[i] = 0
    end
    local cbLeftCardCount = TABLECONST.PAI_TOTAL
    local pai = {Table.pai_1, Table.pai_2, Table.pai_3, Table.pai_4, Table.pai_5}
    if self.PlayerNum == 2 then 
        pai = {Table.pai_1, Table.pai_2, Table.pai_5}
    elseif self.PlayerNum == 3 then 
        pai = {Table.pai_1, Table.pai_2, Table.pai_3, Table.pai_5}
    end
    local iStart = 0
    for k = 1, #pai do
         for i = 1, TABLECONST.MAX_COUNT - 1 do
            cuRepertoryCard[cbLeftCardCount] = pai[k][i]
            if not cuRepertoryCard[cbLeftCardCount] then cuRepertoryCard[cbLeftCardCount] = 0 end
            cbLeftCardCount = cbLeftCardCount - 1
            iStart = iStart + 1
        end
    end
    for i = 1, #Table.endPai do
        cuRepertoryCard[i] = Table.endPai[i]
    end
    cbLeftCardCount = TABLECONST.PAI_TOTAL
    for i = TABLECONST.PAI_TOTAL, 1, -1 do
        if i > (cbLeftCardCount - iStart) and cuRepertoryCard[i] > 0 then 
            for j = 1, cbLeftCardCount do
                if tab_RandCard[j] == cuRepertoryCard[i] then 
                    tab_RandCard[cbLeftCardCount], tab_RandCard[j] = tab_RandCard[j], tab_RandCard[cbLeftCardCount]
                    cbLeftCardCount = cbLeftCardCount - 1
                    cuRepertoryCard[i] = 0  
                    break
                end
            end
        else break
        end
    end
    
    cbLeftCardCount = TABLECONST.PAI_TOTAL
    local iEnd = #Table.endPai
    for i = 1, TABLECONST.PAI_TOTAL do
        if i < iEnd and cuRepertoryCard[i] > 0 then 
            for j = i, cbLeftCardCount - iStart do
                if tab_RandCard[j] == cuRepertoryCard[i] then
                    tab_RandCard[i], tab_RandCard[j] = tab_RandCard[j], tab_RandCard[i]
                    cuRepertoryCard[i] = 0
                    break
                end
            end
        else break
        end
    end
    
    if Table.Banker and Table.Banker >= 0 and Table.Banker <= 3 then self.Banker = Table.Banker end  --设置庄家
    return tab_RandCard
end

function TableLogic:StartFaPai(wJu)
    local tab_RandCard = MjLogic.table_RepertoryCard
    self.cardRepertory = tab_RandCard
	self.LeftCardCount = TABLECONST.PAI_TOTAL
    for i = 1, self.PlayerNum do
        local chair = self:GetChair(i)      
        for j = 1, TABLECONST.NUM_HANDFULL - 1 do       
            local val = tab_RandCard[self.LeftCardCount]
            chair.tabCardVal[#chair.tabCardVal + 1] = val
            chair:AddHandCard(val)
            self.LeftCardCount = self.LeftCardCount - 1
        end
    end
    
    for chair in self:ChairIterator() do
        chair:StartFaPai(wJu)
        chair:UpdataTingData()
	end
    
    if not self:ReportTing() then    --都没有报听的就摸牌
        self:DispatchCard(self:UserIdToChair(self.CurUserId))
        self.PermitOutCard = true
    end
    
    self.CurUserId = self.Banker
end

function TableLogic:ReportTing()
    function HasCouldGang(chair, tingVal)     --为了计算是否有刻子
        local bOk = false
        for i = 1, #tingVal do 
            local ind = MjLogic:ValToIndex(tingVal[i])
            local tabIndx = DeepCopy(chair.tabCbCardIndex)
            tabIndx[ind] = (tabIndx[ind] or 0) + 1
            local tabKsq = {ksq = {k = 0,s = 0,q = 0}}
            local tabWan, tabTiao, tabTong, tabZi = MjLogic:ParsePaiToWTTZ(tabIndx)
            MjLogic:ProcessOneColor(tabTiao, true, tabKsq)
            MjLogic:ProcessOneColor(tabTong, true, tabKsq)
            
            for _, v in pairs(tabKsq.ksq.kv or {}) do
                if chair.tabCbCardIndex[MjLogic:ValToIndex(v)] >= 3 then 
                    bOk = true
                end
            end

        end
        return bOk
    end
    local hasTing = 0
    for chair in self:ChairIterator() do
        if chair.DoneBaoTing == -1 and     --没有处理过报听
           #chair.tabTingCardData ~= 0 and #chair.tabTingCardData.val ~= 0 then 
            local baoTingType = {[false]=1, [true]=2}
            chair.ReportingStat = baoTingType[HasCouldGang(chair, chair.tabTingCardData.val)]  --记录下来
            local msg = string.pack('i2', chair.ReportingStat)
            chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_ReportTing, msg)
            hasTing = hasTing + 1
        end
	end
    if hasTing > 0 then    --告诉别人 有玩家在操作是否报听
        for chair in self:ChairIterator() do
            chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_ReportTingToOther, string.pack('i2', 0))
        end
    end
    self.CouldBaoTing = hasTing     --开局时有多少人可以报听
    return hasTing > 0
end

function TableLogic:ChairIterator(tabCondition)    
    local tabChair = {}
    for i = 1, self.PlayerNum do
        local chair = self:GetChair(i)
        if chair and chair.addr then
            if not (tabCondition and tabCondition.CurId == chair.UserChairID) then         --忽略当前玩家
                if not (tabCondition and tabCondition.OmitHuer and chair.DoneHu) then     --忽略已胡牌的玩家
                    tabChair[#tabChair + 1] = chair
                end
            end
        end
    end
    local i = 0
    return function()
        i = i + 1
        return tabChair[i]
    end
end

function TableLogic:GetChair(chairIndex)  --chairIndex 是以1开始的,而不是1
    return self.chairAct[self.chairIndex[chairIndex]]
end


function TableLogic:DispatchCard(chair, type)    --摸牌
    if self:CheckLiuJu() then 
        self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_ChouZhang)
        return 
    end
    for chair in self:ChairIterator() do
        chair.tabToDo = nil
    end
    if chair == nil then 
        chair = self:UserIdToChair(self.CurUserId)
    end
    local getCard = self:DispatchCardFromRep(chair)
    
    self.tabCurGetCard.getCard = getCard   --玩家当前的牌,用于断线重连
    self.tabCurGetCard.id = chair.UserChairID
    self.tabCurGetCard.leftCard = self.LeftCardCount
    chair:OnDispatchCard(getCard, self.LeftCardCount)
    self.CurUserId = chair.UserChairID
    self:DispatchCardToOthers(chair)
end

function TableLogic:CheckLiuJu()
    local Tables = {}
    local logicPath = skynet.getenv('gamelogic_path')
    if logicPath then 
        local fileFaPai = io.open(logicPath..'FaPai.lua',rb)
        if fileFaPai then fileFaPai:close() 
            Tables = require("FaPai")
        else skynet.error('no fapai file!!!') end
    end

    local Table = {}
    for chair in self:ChairIterator() do
        if Tables[chair.PlayerId] ~= nil then
            Table = Tables[chair.PlayerId]
            break
        end
    end
    
    local nLeft = 0
    if Table.leftCard and Table.leftCard > 0 then nLeft = TABLECONST.PAI_TOTAL - Table.leftCard - (TABLECONST.MAX_COUNT - 1) * self.PlayerNum end
    if self.LeftCardCount <= nLeft then 
        self.LiuJu = true
        local HuData = {LiuJu = true}
        self:GameOver(HuData)
        --skynet.call(self.ItableSrv, "lua", "ConcludeGame", self.TableObj, HuData)
        return true
    end
    return false
end


function TableLogic:DispatchCardToOthers(chair, getCard)    --发牌给别人
    local wUserChairId = chair.UserChairID
    for chair in self:ChairIterator() do
        if chair.UserChairID ~= wUserChairId then 
            chair:OthersCardToMe(wUserChairId, self.LeftCardCount)
        end
    end
end

function TableLogic:DispatchCardFromRep(chair, type)
    local getCard = self.cardRepertory[self.LeftCardCount]
    self.LeftCardCount = self.LeftCardCount - 1
    skynet.error(string.format('id %d get card is %0x!!!!!!!!!',chair.UserChairID, getCard))
    if type ~= 'FangJiang' then chair.LastGetCard = getCard end   --翻将时摸的牌
    return getCard
end

function TableLogic:UserIdToChair(wUserChairId)    --userId 是以0开始的,而不是1
    if not wUserChairId then return nil end
    local chairIndex = wUserChairId + 1
    return self.chairAct[chairIndex]
end

--此三个功能放进平台处理
function TableLogic:WantFaceReq(chair, which)
    local msg = string.pack('I2I4', chair.UserChairID, which or 0)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserWantFaceResult, msg)
end

function TableLogic:WantShortVoiceReq(chair, which)
    local msg = string.pack('I2I4', chair.UserChairID, which or 0)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_UserWantVoiceResult, msg)
end

function TableLogic:SendTextReq(chair, id, content)
    local msg = string.pack('I4c256', id, content)
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_SendTxt, msg)
end
-----------------------------------

function TableLogic:GetNextChair(chair)      --返回下一个有效的玩家
    local idNext = self:GetNextChairId(chair.UserChairID)
    return self:UserIdToChair(idNext)
end

function TableLogic:GetNextChairId(wCurId)   --返回下一个玩家的ID,用在判断吃
    wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
	if self.PlayerNum == 2 then
		if wCurId == 1 or wCurId == 3 then
			wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
		end
	elseif self.PlayerNum == 3 then
		if wCurId == 3 then
			wCurId = (wCurId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER;
		end
	end
	return wCurId;
end

function TableLogic:UpdataTingData(chair)
    chair:UpdataTingData()
end

function TableLogic:OnOutCard(chair, cbCardData)
    local wUserChairId = chair.UserChairID
    self.CurOutCard = cbCardData
    chair:OnOutCard(cbCardData)
    chair.LianGang = 0
    self.LastOutCardId = wUserChairId
    self.tabCurGetCard = {}
    self.CurUserId = wUserChairId
    self:UpdataTingData(chair)
    local tabCouldHu = {}
    local hasPengOrGang = false
    
    for chair in self:ChairIterator() do 
        local dataToSend = string.pack('<I2B', wUserChairId, cbCardData)
        chair.OperateBit = 0
        local couldHu, couldPengOrGang = false, false
        if chair.UserChairID ~= wUserChairId and not chair.DoneHu then
            couldHu = chair:CanHu(cbCardData, wUserChairId)
            couldPengOrGang = chair:CanPeng(cbCardData, wUserChairId)
            if couldPengOrGang then chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_PENG end
            local bGang = chair:CanGang(cbCardData, WIKTYPE.WIK_JIEGANG, wUserChairId)
            if bGang then chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_JIEGANG end
            couldPengOrGang = bGang or couldPengOrGang
            if couldHu then table.insert(tabCouldHu, chair.UserChairID) chair.OperateBit = chair.OperateBit|WIKTYPE.WIK_HU end
        end
        if couldPengOrGang then hasPengOrGang = true end
        dataToSend = dataToSend..string.pack('bb', ({[true]=1,[false]=0})[couldPengOrGang or couldHu] or 0, 0)
        chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_UserOutCard, dataToSend)
    end
    
    local hasPGH = false
    for chair in self:ChairIterator({OmitHuer = true, CurId = wUserChairId}) do
        if (chair.OperateBit&(WIKTYPE.WIK_PENG|WIKTYPE.WIK_HU)) > 0 then 
            hasPGH = true 
            chair:SendOperateHint()
        end
    end
    
    if (not hasPengOrGang) and (#tabCouldHu == 0) then 
        self:SetNextUser()
        self:DispatchCard()
    end
end

function TableLogic:SetNextUser()
    self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
    self:ValidCurrentUserChairId()
    
    if self:UserIdToChair(self.CurUserId).DoneHu then     --如果该玩家已经胡了
        self:SetNextUser()
    end
end

function TableLogic:ValidCurrentUserChairId()       --修正2,3人麻将下一个玩家的问题
    if self.PlayerNum == 2  then
        if self.CurUserId == 1 or self.CurUserId == 3 then
            self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
        end
    elseif self.PlayerNum == 3 then
        if self.CurUserId == 3 then
            self.CurUserId = (self.CurUserId + TABLECONST.FULL_PLAYER + 1) % TABLECONST.FULL_PLAYER
        end
    end
    return self.CurUserId
end

HuPaiResult = {}
function HuPaiResult:New(obj)
    obj = obj or {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end

function HuPaiResult:GetPackString()
    local tTF = {[true]=1, [false]=0}
    local bufData = string.pack('B', tTF[self.ChaJiao or false])            --是否有叫
    for i = 1, TABLECONST.FULL_PLAYER do           --每个人1 有叫，2无叫 3报听 4已经胡牌用户
        bufData = bufData..string.pack('i4', self.typeChaJiao[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do           --查叫环节分数输赢
        bufData = bufData..string.pack('i4', self.chaJiaoFen[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do           --cbHuPatten
        for j = 1, 6 do
            bufData = bufData..string.char(self.huPatten[i][j] or 0)
        end
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人胡的牌
        bufData = bufData..string.pack('b', self.huPaiData[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人是否胡
        bufData = bufData..string.pack('b', tTF[self.bHu[i] or false])   
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人的分数
        bufData = bufData..string.pack('i4', self.gameScoreJu[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人手牌的数量
        bufData = bufData..string.char(#self.standCard[i])
    end
    for i = 1, TABLECONST.FULL_PLAYER do          --每个人的手牌
        for j = 1, TABLECONST.MAX_COUNT do
            local standPai = self.standCard[i][j]
            bufData = bufData..string.char(standPai or 0)
        end
    end
    bufData = bufData..string.pack('bbbb',0,0,0,0)  --买马的数量
    bufData = bufData..BufTool.WriteOffset(80)      --买马的数据80 = 2 * 4 * 10
    bufData = bufData..string.pack('bbbb',0,0,0,0)  --是否封胡
    
    for i = 1, TABLECONST.FULL_PLAYER do
        local len = #self.huPaiMsg[i]
        if len > 0 then 
            local len = string.len(self.huPaiMsg[i])
            bufData = bufData..self.huPaiMsg[i]
            bufData = bufData..BufTool.WriteOffset(256 - len)
        else bufData = bufData..BufTool.WriteOffset(256) end
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do          --胡牌的番数 FanShu
        bufData = bufData..string.pack('i4',self.huShuJu[i])
    end
    
    bufData = bufData..string.pack('bbbb',0,0,0,0)      --报听的数据1报听，0没有报听
    bufData = bufData..string.pack('i4i4i4i4',0,0,0,0)  --胡牌的个数
    
    return bufData
end

function TableLogic:ConcludeGame(huData)
    if self.HasConclude then return end
    
    if self:ShouldChaJiao() then     --查叫次数
        for chair in self:ChairIterator() do
            if not chair.DoneHu then 
                Increment(self.totalResult[7], chair.UserChairID, 1, 7)
            end
        end
    end
    
    if not self.Huer or #self.Huer <= 1 then    --最多一家胡，且报听了没有胡，就反查叫
        for chair in self:ChairIterator() do 
            if chair.DoneBaoTing and not chair.DoneHu then
                Increment(self.totalResult[8], chair.UserChairID, 1, 8)
            end
        end
    end
    
    function IsTing(chair)  --1 有叫，2无叫 3报听 4 已经胡牌用户
        return (chair.tabTingCardData and #chair.tabTingCardData ~= 0 and #chair.tabTingCardData.val ~= 0)
    end
        
    local bZiMo = huData.ZiMo or false
    self.Banker = self:GetNewBanker(huData.LiuJu)     --设置新的庄家
    if huData.LiuJu then
        self.LiuJuNum = (self.LiuJuNum or 0) + 1
        if self:ShouldChaJiao() then    --只有查叫才能算分
            local scoreWin = 0
            local tabNotting = {}
            local tabTing = {}
            for chair in self:ChairIterator() do
                if IsTing(chair) then   
                    local perScore, fan = chair:CalScore()
                    chair.FanShu = fan
                    scoreWin = scoreWin + perScore
                    chair.GameScoreJu = perScore
                    table.insert(tabTing, chair)
                else  
                    table.insert(tabNotting, chair)
                end
            end
            if #tabTing == 1 then   --一个人听
                tabTing[1].GameScoreJu = tabTing[1].GameScoreJu * (#tabNotting)
                for _, chair in pairs(tabNotting) do
                    chair.GameScoreJu = scoreWin * (-1)
                end
            else       --有两人听
                tabNotting[1].GameScoreJu = scoreWin * (-1)
            end
            for chair in self:ChairIterator() do     --最终得分
                chair.ChaJiaoFen = chair.GameScoreJu or 0
                chair.GameScoreJu = chair.GameScoreJu + (chair.GangScore or 0)
                chair.GameScoreJu = chair.GameScoreJu * (TableConfig.DiFen or 1)
            end
        end
    end
    
    for chair in self:ChairIterator() do
        chair:ConcludeGame(huData)
    end
    
    function GetHuPatten(chair)  --1自摸，2胡牌，3点炮，4.一炮多响 5有叫 6 无叫 7 报听
        local tabPatten = {}
        if chair.tabHuInfo.Hu then    --胡牌了
            local tZiMo = {[true]=1,[false]=2}
            tabPatten[#tabPatten + 1] = tZiMo[chair.tabHuInfo.ZiMo or false]
            for ch in self:ChairIterator({CurId = chair.UserChairID}) do    --胡牌了也可能之前点炮
                if ch.tabHuInfo.ProviderId == chair.UserChairID then  
                    tabPatten[#tabPatten + 1] = 3
                    break
                end
            end
        else 
            if chair.DoneBaoTing > 0 then tabPatten[#tabPatten + 1] = 7 end
            if self:ShouldChaJiao() then     --需要显示查叫才显示
                local ting = {[true]=5,[false]=6}
                tabPatten[#tabPatten + 1] = ting[IsTing(chair)]
            end
            local dpInfo = chair.tabHuInfo.DianPaoInfo
            if dpInfo then
                local dx = {[true]=4,[false]=3}
                local bDx = false
                if #dpInfo > 1 then 
                    if dpInfo[1].Lc == dpInfo[2].Lc then bDx = true end  --点炮两次，且是同一张牌时才叫多响
                end
                tabPatten[#tabPatten + 1] = dx[bDx]
            end
        end
        return tabPatten
    end
   
    local huPaiResult = {ChaJiao=self:ShouldChaJiao(),typeChaJiao={2,2,2,2},chaJiaoFen={0,0,0,0},huPatten={{},{},{},{}},huPaiData={0,0,0,0}, CardData=0, bHu={false,false,false,false},gameScoreJu={0,0,0,0},huShuJu={0,0,0,0},standCard={{},{},{},{}},huPaiMsg={"","","",""}}
    local result = HuPaiResult:New(huPaiResult)
    result.CardData = huData.HuCardData
    for chair in self:ChairIterator() do
        if chair then
            local chairIndex = chair.UserChairID + 1
            result.bHu[chairIndex] = chair.DoneHu
            
            if chair.DoneHu then result.typeChaJiao[chairIndex] = 4 
            elseif IsTing(chair) then result.typeChaJiao[chairIndex] = 1
            elseif chair.DoneBaoTing > 0 then result.typeChaJiao[chairIndex] = 3
            end
            result.chaJiaoFen[chairIndex] = chair.ChaJiaoFen or 0
            result.huPatten[chairIndex] = GetHuPatten(chair)
            result.huPaiData[chairIndex] = chair.tabHuInfo.CardData or 0
            result.gameScoreJu[chairIndex] = chair.GameScoreJu or 0
            print("chairIndex = "..chairIndex.." GameScoreJu"..result.gameScoreJu[chairIndex])
            result.huShuJu[chairIndex] = chair.FanShu or 0
            local standCard = chair:GetStandCard()
            result.standCard[chairIndex] = chair.standCard or {}
            result.huPaiMsg[chairIndex] = chair.ResultMsg or ""
        end
    end
    local dataBuf = result:GetPackString()
    self:SendMsgToAll(CMD.Sub_GameSvrToClient_TableModle_CommonHuPaiResult, dataBuf)
    self.HasConclude = true
    self:UpdataChairs(huData)
    for chair in self:ChairIterator() do
        local chair_obj = self:GetSeatByChairId(chair.UserChairID)
        chair_obj.Player.nScore = (chair_obj.Player.nScore or 0) + chair.GameScoreJu
    end
    
    for chair in self:ChairIterator() do
        Increment(self.totalResult[1], chair.UserChairID, chair.GameScoreJu, 1)
    end

    self.room.ConcludeGameFriend()
    function ClearChairData()
        for chair in self:ChairIterator() do
            chair.GameScoreJu = 0
            chair.standCard = {}
            chair.ResultMsg = ''
            chair.DoneBaoTing = -1
            chair.tabHuInfo = {}
            chair.FanShu = 0
            chair.GangDes = ''
            chair.GangScore = 0
            chair.ChaJiaoFen = 0
        end
        self.LiuJu = false
        self.Huer = {}
    end
    ClearChairData()

    return false
end

function TableLogic:ShouldChaJiao()    --是否需要查叫
    function IsTing(chair)  
        return (chair.tabTingCardData and #chair.tabTingCardData ~= 0 and #chair.tabTingCardData.val ~= 0)
    end
    local nHuer, nTinger, nNTinger = 0, 0, 0    --胡，听了，没听(报听了没胡算没听)
    local tabNotting = {}
    for chair in self:ChairIterator() do
        if chair.DoneHu then nHuer = nHuer + 1
        else
            if IsTing(chair) and chair.DoneBaoTing <= 0 then   --听了且开头没有报听
                nTinger = nTinger + 1                    
            else nNTinger = nNTinger + 1 end
        end
        if not IsTing(chair) then table.insert(tabNotting, chair.UserChairID) end   --计算没有听的，用于计算新的庄家
    end
    if nHuer >= 2 then return false    --有2个胡了
    else return (nTinger * nNTinger ~= 0), tabNotting end --一个胡了或者都没胡,那么有不听者和听者同时存在就查
end

function TableLogic:GetNewBanker(liuJu)
    if not liuJu then 
        if #self.Huer == 1 then                                            --只有一个人胡
            return self.Huer[1].Id
        elseif #self.Huer == 2 then
            if (not self.Huer[1].ZiMO and not self.Huer[2].ZiMO) and       --一炮多响
               (self.Huer[1].Lc == self.Huer[2].Lc) then 
               return self.Huer[1].ProviderId
            else
                return self.Huer[1].Id                                     --第一人胡的是庄
            end
        end
    else
        local bCj, tabNotting = self:ShouldChaJiao()
        if bCj then
            if #tabNotting == 1 then return tabNotting[1]   --1个玩家无叫，2个玩家有叫，则无叫玩家当庄
            elseif #tabNotting == 2 then
                local zhuangjiao = 0                        --默认庄家有叫
                for i = 1, #tabNotting do
                    if self.Banker == tabNotting[i] then    --庄家无叫
                       zhuangjiao = i
                       break
                    end
                end
                if zhuangjiao == 0 then                      --庄家有叫，则庄家下家当庄
                    return self:GetNextChairId(self.Banker)  
                else                                         --庄家无叫，则另外一个无叫玩家坐庄
                    if zhuangjiao == 1 then
                        return tabNotting[2] 
                    else return tabNotting[1] end
                end
            end 
        end
    end
    return self.Banker
end

function TableLogic:CalScore(huID, providerId)   --计算得分
    function ClearScore()
        for chair in self:ChairIterator() do
            --chair.GameScoreJu = 0
            --chair.HuShu = 0
        end
    end
    ClearScore()
    
    local huChair = self:UserIdToChair(huID)
    local dpChair = self:UserIdToChair(providerId)
    local score, fan = huChair:CalScore()
    score = score * (TableConfig.DiFen or 1)
    huChair.FanShu = fan
    
    print('$$$$$$$$$Id ', huChair.UserChairID, ' Hu, score is ', score, ' FanShu is ', fan)
    
    local HadHuId
    for chair in self:ChairIterator({CurId = huID}) do     --忽略掉已经胡了的人
        if chair.DoneHu and chair.UserChairID ~= huID then 
            HadHuId = chair.UserChairID
        end
    end
    
    local tabSingleScore = {[0]=0,[1]=0,[2]=0,[3]=0}    --每胡一次的记分，用于胡牌动画
    if huChair.tabHuInfo.ZiMo then      --自摸了每个人都要减分
        local nLost = 0
        for chair in self:ChairIterator({CurId = HadHuId}) do
            chair.GameScoreJu = chair.GameScoreJu + score * (-1)
            nLost = nLost + 1
            tabSingleScore[chair.UserChairID] = score * (-1)
        end
        huChair.GameScoreJu = huChair.GameScoreJu + score * nLost
        tabSingleScore[huID] = score * nLost
    else
        if dpChair then 
            dpChair.GameScoreJu = dpChair.GameScoreJu + score * (-1) 
            huChair.GameScoreJu = huChair.GameScoreJu + score
            tabSingleScore[providerId] = score * (-1)
            tabSingleScore[huID] = score 
        end
    end
    
    return tabSingleScore
end

function TableLogic:GetSeatByChairId(chairId)
    for _,seat in pairs(self.m_pChairs) do
        if seat.m_wChairId == chairId then
            return seat
        end
    end
    return nil
end

function TableLogic:UpdataChairs(huData)     --数据填充到平台上,累积每局
    self.room.m_nBanker = self.Banker
    for chair in self:ChairIterator() do
        local chairObj = self:GetSeatByChairId(chair.UserChairID)
        if not chairObj then print('chairObj is not ok '..chair.UserChairID) end
        chairObj.nScores = chairObj.nScores + chair.GameScoreJu
        chairObj.nScoreJu = chair.GameScoreJu -- 把每局得分保存到平台去
        chairObj.nMingGang = chairObj.nMingGang + (chair.nMingGang or 0)
        chairObj.nAnGang = chairObj.nAnGang + (chair.nAnGang or 0)
        if chair.UserChairID == huData.HuId then 
            chairObj.m_nHuPaiTotal = (chairObj.m_nHuPaiTotal or 0) + 1
        end
        if chair.UserChairID == huData.ProviderId then 
            chairObj.nDiaoPao = (chairObj.nDiaoPao or 0) + 1
        end
    end
end


function TableLogic:SendMeOfflineBackData(Player, wUserChairId) 
    skynet.error('SendMeOfflineBackData Id:', wUserChairId, 'CurUserId is ', self.CurUserId)
    local chair = self:UserIdToChair(wUserChairId)
    if self.HasConclude then    --结算时断线
        print('SendMeOfflineBackData in ConcludeGame---------------------------')
        chair.GameState = GameState.ready   --这时候就准备
        self:CheckStartGame()
        return
    end
    
    local bufData = ''
    bufData = bufData..string.pack('I2I2', self.Banker, self.CurUserId)  --庄家和当前用户
    bufData = bufData..chair.tabUserAction:GetPackString()
    local myGetCard = 0
    local standCard = chair:GetStandCard()
    if self.CurUserId == chair.UserChairID and #standCard % 3 == 2 then  --当前玩家,要展现14张牌
        myGetCard = self.tabCurGetCard.getCard or 0 
    end  
    print('############ myGetCard is ', myGetCard, ' #standCard is ', #standCard)
    if chair.tabHuInfo.Hu then myGetCard = chair.tabHuInfo.CardData end
    bufData = bufData..string.pack('BB', self.LeftCardCount, myGetCard or 0)  --剩余数量和刚才摸的牌,如果他不是当前玩家,就为0
    
    if self.CurUserId == chair.UserChairID and self.tabCurGetCard.id == chair.UserChairID then
        local ind = MjLogic:ValToIndex(self.tabCurGetCard.getCard)
        chair.tabCbCardIndex[ind] = chair.tabCbCardIndex[ind] - 1   --减掉刚刚摸的牌，因为本身就有了
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do            --WORD        StandCardCount[GAME_PLAYER];
        local chair = self.chairAct[i]
        if chair then 
            if chair.UserChairID == wUserChairId then 
                bufData = bufData..string.pack('I2', #standCard)
            else 
                bufData = bufData..string.pack('I2', #chair:GetStandCard())
            end
        else bufData = bufData..string.pack('I2', 0) end 
    end
    
    bufData = bufData..chair:SendMeOfflineBackData('standCard')
    
    local strStand = ''
    for i = 1, #standCard do
        strStand = strStand..string.format(' %0x', standCard[i])
    end
    print('######### strStand is ', strStand)

    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..string.pack('I2', #chair.tabWeaveItem)   
        else bufData = bufData..string.pack('I2', 0) end
    end

    for i = 1, TABLECONST.FULL_PLAYER do        --tagWeaveItem    arrWeaveItem[GAME_PLAYER][MaxWeaveCount];
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..chair:SendMeOfflineBackData('weaveItem', wUserChairId)   
        else bufData = bufData..BufTool.WriteOffset(6 * TABLECONST.MAXWEAVCOUNT) end 
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..string.pack('I2', #(chair.tabCbOutCard or {}))
        else bufData = bufData..string.pack('I2', 0) end
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..chair:SendMeOfflineBackData('outCard')   
        else bufData = bufData..BufTool.WriteOffset(TABLECONST.MAXOUTCARDCOUNT) end
    end
    
    bufData = bufData..string.pack('bbbb', 0,0,0,0)       --是否封胡
    
    for i = 1, TABLECONST.FULL_PLAYER do   --选择报听的结果
        local chair = self.chairAct[i]
        if chair then 
            local bt = chair.DoneBaoTing or 0
            if bt < 0 then bt = 0 end
            bufData = bufData..string.pack('i4', bt)
        else bufData = bufData..string.pack('i4', 0)
        end
    end
   
    local lenTing = 0
    if chair.tabTingCardData and chair.tabTingCardData.val then lenTing = #chair.tabTingCardData.val end    
    bufData = bufData..string.pack('B', lenTing)
    bufData = bufData..chair:SendMeOfflineBackData('tingData')
    
    bufData = bufData..BufTool.WriteOffset(128)
    bufData = bufData..string.pack('i4', self.PlayerNum or 3)
    
    bufData = bufData..string.pack('i4i4i4i4', 0,0,0,0)   --是否可以报听
    for i = 1, TABLECONST.FULL_PLAYER do   --是否胡
        local chair = self.chairAct[i]
        if chair then 
            local temp = {[true] = 1,[false] = 0}
            bufData = bufData..string.pack('i4', temp[chair.tabHuInfo.Hu or false])
        else bufData = bufData..string.pack('i4', 0)
        end
    end
    
    for i = 1, TABLECONST.FULL_PLAYER do   --胡的值
        local chair = self.chairAct[i]
        if chair then 
            bufData = bufData..string.pack('b', chair.tabHuInfo.CardData or 0)
            print(string.format('$$$$$$$$$$$ chair id %d, Hu is %d', chair.UserChairID, chair.tabHuInfo.CardData or 0))
        else bufData = bufData..string.pack('b', 0)
        end
    end
       
    chair:SendDataInLua(CMD.Sub_GameSvrToClient_TableModle_OfflineBackData, bufData)
    
    if not self.PermitOutCard then 
        if not chair.tabHuInfo.Hu then self:ReportTing() end
    else 
        if self.CurUserId == chair.UserChairID then 
            print('SendMeOfflineBackData DispatchCard Agin , id', chair.UserChairID, 'cur card is ', self.tabCurGetCard.getCard)
            if self.tabCurGetCard.id == chair.UserChairID then
                chair:OnDispatchCard(self.tabCurGetCard.getCard, self.LeftCardCount)
            end
            self.CurUserId = chair.UserChairID
        end
    end
    
end

function TableLogic:IsPlaying()
    return self.room.m_nGameState ~= 2
end

--看看是否有托管的
function TableLogic:CheckStandBy()
    print('##########chaoshi CheckStandBy')
    for chair in self:ChairIterator() do  --先检测是否有吃碰杠胡的人
        if chair.tuoguan then
            if chair.OperateBit > 0 then
                if chair.OperateBit & WIKTYPE.WIK_HU then
                    --TODo 有胡牌的自动胡
                else
                    --发送过的消息
                end
            end
        end
    end
    --再检测是否是该玩家出牌
    if self.CurUserId then
        --ToDo 如果是该玩家出牌那就出牌
    end
end
--看看是否有超时的
function TableLogic:ActionTimeOut()
    print('##########chaoshi ActionTimeOut')
    for chair in self:ChairIterator() do  --先检测是否有吃碰杠胡的人
        if chair.tuoguan then
            if chair.OperateBit > 0 then
                if chair.OperateBit & WIKTYPE.WIK_HU then

                else
                    
                end
            end
        end
    end
    --再检测是否是该玩家出牌
    if self.CurUserId then

    end
end

return TableLogic